Runtime常用方法和一些应用
Runtime方法列表
|
|
获取列表(属性、方法、协议)
|
|
相关的定义
|
|
类在runtime中的表示
|
|
方法调用在运行时的过程
- 如果调用实例方法,会到实例的isa指针指向的对象(也就是类对象)操作。
如果调用的是类方法,会到类对象的isa指针指向的对象(也就是元类对象)中操作。
- 在相应操作的对象中的缓存方法列表中找调用的方法,如果找到,转向相应实现并执行。
- 如果没找到,在相应操作的对象中的方法列表中找调用的方法,如果找到,转向相应实现执行
- 如果没找到,去父类指针所指向的对象中执行1,2.
- 以此类推,如果一直到根类还没找到,转向
拦截调用。 - 如果没有重写
拦截调用的方法,程序报错。
- 在相应操作的对象中的缓存方法列表中找调用的方法,如果找到,转向相应实现并执行。
拦截调用
拦截调用就是,在找不到调用的方法程序崩溃之前,你有机会通过重写NSObject的四个方法来处理。
- 第一个方法是当你调用一个不存在的类方法的时候,会调用这个方法,默认返回NO,你可以加上自己的处理然后返回YES。
- 第二个方法和第一个方法相似,只不过处理的是实例方法。
- 第三个方法是将你调用的不存在的方法重定向到一个其他声明了这个方法的类,只需要你返回一个有这个方法的target。
- 第四个方法是将你调用的不存在的方法打包成NSInvocation传给你。做完你自己的处理后,调用invokeWithTarget:方法让某个target触发这个方法。
动态添加方法
重写了拦截调用的方法并且返回了YES,我们要怎么处理呢?
有一个办法是根据传进来的SEL类型的selector动态添加一个方法。
首先从外部隐式调用一个不存在的方法:
然后,在target对象内部重写拦截调用的方法,动态添加方法。
其中class_addMethod的四个参数分别是:
- Class cls 给哪个类添加方法,本例中是self
- SEL name 添加的方法,本例中是重写的拦截调用传进来的selector。
- IMP imp 方法的实现,C方法的方法实现可以直接获得。如果是OC方法,可以用
+ (IMP)instanceMethodForSelector:(SEL)aSelector;获得方法的实现。 - “v@:*”方法的签名,代表有一个参数的方法。
关联对象
现在你准备用一个系统的类,但是系统的类并不能满足你的需求,你需要额外添加一个属性。
这种情况的一般解决办法就是继承。
但是,只增加一个属性,就去继承一个类,总是觉得太麻烦类。
这个时候,runtime的关联属性就发挥它的作用了。
objc_setAssociatedObject的四个参数:
- id object给谁设置关联对象。
- const void *key关联对象唯一的key,获取时会用到。
- id value关联对象。
- objc_AssociationPolicy关联策略,有以下几种策略:
|
|
objc_getAssociatedObject的两个参数。
- id object获取谁的关联对象。
- const void *key根据这个唯一的key获取关联对象。
其实,你还可以把添加和获取关联对象的方法写在你需要用到这个功能的类的类别中,方便使用。
注意:这里面我们把getAssociatedObject方法的地址作为唯一的key,_cmd代表当前调用方法的地址。
方法交换
方法交换,就是将两个方法的实现交换。例如,将A方法和B方法交换,调用A方法的时候,就会执行B方法中的代码,反之亦然。
话不多说,这是参考Mattt大神在NSHipster上的文章自己写的代码。
|
|
在一个自己定义的viewController中重写viewWillAppear
|
|
我的理解:
- 方法交换对于我来说更像是实现一种思想的最佳技术:AOP面向切面编程。
- 既然是切面,就一定不要忘记,交换完再调回自己。
- 一定要保证只交换一次,否则就会很乱。
- 最后,据说这个技术很危险,谨慎使用。